package com.joycessh.controller;


import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.joycessh.common.lang.Result;
import com.joycessh.entity.*;
import com.joycessh.vo.PostVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import com.joycessh.controller.BaseController;

import javax.validation.Valid;
import java.util.*;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author Joycessh
 * @since 2019-08-18
 */
@Slf4j
@Controller
public class PostController extends BaseController {

    private static final String KAPTCHA_SESSION_KEY = "KAPTCHA_SESSION_KEY";

    @ResponseBody
    @GetMapping("/hots")
    public Result hotPosts() {
        // 从缓存中获取最近7天的热点文章
        Set<ZSetOperations.TypedTuple> lastWeekRank = redisUtil.getZSetRank("last_week_rank", 0, 6);

        List<Map<String, Object>> hotPosts = new ArrayList<>();
        for (ZSetOperations.TypedTuple typedTuple : lastWeekRank) {
            Map<String, Object> map = new HashMap<>();
            map.put("comment_count", typedTuple.getScore());
            map.put("id", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:id"));
            map.put("title", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:title"));
            hotPosts.add(map);
        }
        return Result.succ(hotPosts);
    }

    @RequestMapping("/category/{id:\\d*}")
    public String category(@PathVariable Long id) {
        Page page = getPage();

        IPage<PostVo> pageData = postService.paging(page, null, id, null, null, "create_time");
        req.setAttribute("pageData", pageData);
        req.setAttribute("currentCategoryId", id);

        return "post/category";
    }

    @RequestMapping("/post/{id:\\d*}")
    public String view(@PathVariable Long id) {

        QueryWrapper wrapper = new QueryWrapper<Post>()
                .eq(id != null, "p.id", id);

        PostVo vo = postService.selectOne(wrapper);

        IPage commentPage = commentService.paging(getPage(), null, id, "id");

        req.setAttribute("post", vo);
        req.setAttribute("pageData", commentPage);
        req.setAttribute("currentCategoryId", vo.getCategoryId());

        return "post/view";
    }

    @GetMapping("/post/edit")
    public String edit() {
        String id = req.getParameter("id");
        Post post = new Post();
        if(!StringUtils.isEmpty(id)) {
            post = postService.getById(Long.valueOf(id));
            Assert.notNull(post, "文章已被删除！");
            Long profileId = getProfileId();
            Assert.isTrue(post.getUserId()==getProfileId(), "无权限编辑此文章！");
        }

        List<Category> categories = categoryService.list(new QueryWrapper<Category>()
                .orderByDesc("order_num"));

        req.setAttribute("post", post);
        req.setAttribute("categories", categories);
        return "post/edit";
    }

    @ResponseBody
    @Transactional
    @PostMapping("/post/submit")
    public Result submit(@Valid Post post, BindingResult bindingResult, String captcha) throws JsonProcessingException {

//        if(!"2".equals(vercode)) {
//            return Result.fail("人类认证错误！");
//        }

        String kaptcha = (String) SecurityUtils.getSubject().getSession().getAttribute(KAPTCHA_SESSION_KEY);
        if (!kaptcha.equalsIgnoreCase(captcha)) {
            return Result.fail("验证码不正确！");
        }

        if(bindingResult.hasErrors()) {
            return Result.fail(bindingResult.getFieldError().getDefaultMessage());
        }

        if(post.getId() == null) {
            post.setUserId(getProfileId());

            post.setCommentCount(0);
            post.setEditMode(null);
            post.setLevel(0);
            post.setRecommend(false);
            post.setViewCount(0);
            post.setVoteDown(0);
            post.setVoteUp(0);

        } else {
            Post tempPost = postService.getById(post.getId());
            Assert.isTrue(tempPost.getUserId()==getProfileId(), "无权限编辑此文章！");
        }

        postService.saveOrUpdate(post);

        return Result.succ("发布成功", null, "/post/" + post.getId());
    }

    @ResponseBody
    @Transactional
    @PostMapping("/post/delete")
    public Result delete(Long id) {
        Post post = postService.getById(id);

        Assert.notNull(post, "该帖子已被删除");
        Assert.isTrue(post.getUserId()==getProfileId(), "无权限删除此文章！");

        // 清空持久化数据和重新缓存
        postService.delete(id);

        // 删除相关消息、收藏等
        userMessageService.removeByMap(MapUtil.of("post_id", id));
        userCollectionService.removeByMap(MapUtil.of("post_id", id));

        return Result.succ("删除成功", null, "/center");
    }

    @ResponseBody
    @Transactional
    @PostMapping("/post/reply")
    public Result reply(Long pid, Long parentId, String content) {
        Assert.notNull(pid, "找不到对应文章！");
        Assert.hasLength(content, "评论内容不能为空！");

        Post post = postService.getById(pid);
        Assert.isTrue(post != null, "该文章已被删除");

        Comment comment = new Comment();
        comment.setPostId(pid);
        comment.setContent(content);
        comment.setUserId(getProfileId());
        comment.setLevel(0);
        comment.setVoteDown(0);
        comment.setVoteUp(0);
        commentService.save(comment);

        // 评论数量加一
        post.setCommentCount(post.getCommentCount() + 1);
        postService.saveOrUpdate(post);

        //更新首页排版版的评论数量
        postService.incrZsetValueAndUnionForLastWeekRank(comment.getPostId(), true);

        // 通知作者
        UserMessage message = new UserMessage();
        message.setPostId(pid);
        message.setCommentId(comment.getId());
        message.setFromUserId(getProfileId());
        message.setToUserId(post.getUserId());
        message.setType(1);
        message.setContent(comment.getContent());
        userMessageService.save(message);

        // 通知@的人
        if(content.startsWith("@")) {
            String username = content.substring(1, content.indexOf(" "));
            System.out.println(username);
            QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", username);
            User user = userService.getOne(wrapper);
            if(user != null) {
                UserMessage message2 = new UserMessage();
                message.setPostId(pid);
                message2.setCommentId(comment.getId());
                message2.setFromUserId(getProfileId());
                message2.setToUserId(user.getId());
                message2.setType(3);
                message2.setContent(comment.getContent());
                userMessageService.save(message2);
            }
        }

        return Result.succ("评论成功", null, "/post/" + pid);
    }

    @RequiresAuthentication
    @ResponseBody
    @Transactional
    @PostMapping("/post/jieda-delete/")
    public Result reply(Long id) {

        log.info("--------------->进行删除评论操作: id: {}", id);

        Assert.notNull(id, "评论id不能为空！");

        Comment comment = commentService.getById(id);

        Assert.notNull(comment, "找不到对应评论！");

        if(comment.getUserId() != getProfileId()) {
            return Result.fail("不是你发表的评论！");
        }
        commentService.removeById(id);

        // 评论数量减一
        Post post = postService.getById(comment.getPostId());
        post.setCommentCount(post.getCommentCount() - 1);
        postService.saveOrUpdate(post);

        // 缓存中已存在该文章时，才能减，评论数量减一
        String key = "rank_post_" + post.getId();
        boolean isExist = redisUtil.hasKey(key);
        if (isExist) {
            postService.incrZsetValueAndUnionForLastWeekRank(comment.getPostId(), false);
        }

        return Result.succ(null);
    }

}
